#include "stdafx.h"
#include "Camera.h"

Camera& GetCamera()
{
	static Camera camera;
	return camera;
}

Camera::Camera()
{
	mPosition = XMFLOAT3(0.0f, 0.0f, -10.0f);
	mRight    = XMFLOAT3(1.0f, 0.0f, 0.0f);
	mUp       = XMFLOAT3(0.0f, 1.0f, 0.0f);
	mLook     = XMFLOAT3(0.0f, 0.0f, 1.0f);

	XMMATRIX tmp = XMMatrixIdentity();
	XMStoreFloat4x4(&mView, tmp);
	XMStoreFloat4x4(&mProj, tmp);

	rebuildView();
}

Camera::~Camera()
{
}

XMFLOAT3& Camera::position()
{
	return mPosition;
}

XMFLOAT4X4 Camera::view()const
{
	return mView;
}

XMFLOAT4X4 Camera::proj()const
{
	return mProj;
}

void Camera::setLens(float fovY, float aspect, float zn, float zf)
{
	XMMATRIX tmp = XMMatrixPerspectiveFovLH(fovY, aspect, zn, zf);
	XMStoreFloat4x4(&mProj, tmp);
}

void Camera::strafe(float d)
{
	XMVECTOR right = XMLoadFloat3(&mRight);
	right = XMVectorMultiply(right, XMVectorReplicate(d));
	XMVECTOR pos = XMLoadFloat3(&mPosition);
	pos = XMVectorAdd(pos, right);
	XMStoreFloat3(&mPosition, pos);
	//mPosition += d*mRight;
}

void Camera::walk(float d)
{
	XMVECTOR look = XMLoadFloat3(&mLook);
	look = XMVectorMultiply(look, XMVectorReplicate(d));
	XMVECTOR pos = XMLoadFloat3(&mPosition);
	pos = XMVectorAdd(pos, look);
	XMStoreFloat3(&mPosition, pos);
	//mPosition += d*mLook;
}

void Camera::pitch(float angle)
{
	XMMATRIX rot = XMMatrixRotationAxis(XMLoadFloat3(&mRight), angle);

	XMStoreFloat3(&mUp, XMVector3TransformNormal(XMLoadFloat3(&mUp), rot));
	XMStoreFloat3(&mLook, XMVector3TransformNormal(XMLoadFloat3(&mLook), rot));

	/*D3DXMATRIX R;
	D3DXMatrixRotationAxis(&R, &mRight, angle);

	D3DXVec3TransformNormal(&mUp, &mUp, &R);
	D3DXVec3TransformNormal(&mLook, &mLook, &R);*/
}

void Camera::rotateY(float angle)
{
	XMMATRIX rot = XMMatrixRotationY(angle);
	XMStoreFloat3(&mRight, XMVector3TransformNormal(XMLoadFloat3(&mRight), rot));
	XMStoreFloat3(&mUp, XMVector3TransformNormal(XMLoadFloat3(&mUp), rot));
	XMStoreFloat3(&mLook, XMVector3TransformNormal(XMLoadFloat3(&mLook), rot));

	//D3DXMATRIX R;
	//D3DXMatrixRotationY(&R, angle);

	//D3DXVec3TransformNormal(&mRight, &mRight, &R);
	//D3DXVec3TransformNormal(&mUp, &mUp, &R);
	//D3DXVec3TransformNormal(&mLook, &mLook, &R);
}

void Camera::rebuildView()
{
	// Keep camera's axes orthogonal to each other and of unit length.

	XMVECTOR look = XMVector3Normalize(XMLoadFloat3(&mLook));
	//D3DXVec3Normalize(&mLook, &mLook);

	XMVECTOR right = XMLoadFloat3(&mRight);

	XMVECTOR up = XMVector3Cross(look, right);
	up = XMVector3Normalize(up);

	//D3DXVec3Cross(&mUp, &mLook, &mRight);
	//D3DXVec3Normalize(&mUp, &mUp);

	right = XMVector3Cross(up, look);
	right = XMVector3Normalize(right);

	//D3DXVec3Cross(&mRight, &mUp, &mLook);
	//D3DXVec3Normalize(&mRight, &mRight);

	XMVECTOR pos = XMLoadFloat3(&mPosition);

	XMVECTOR dot;
	dot = XMVector3Dot(pos, right);
	float x = -XMVectorGetX(dot);

	dot = XMVector3Dot(pos, up);
	float y = -XMVectorGetX(dot);

	dot = XMVector3Dot(pos, look);
	float z = -XMVectorGetX(dot);

	XMStoreFloat3(&mLook, look);
	XMStoreFloat3(&mRight, right);
	XMStoreFloat3(&mUp, up);

	// Fill in the view matrix entries.
	/*float x = -D3DXVec3Dot(&mPosition, &mRight);
	float y = -D3DXVec3Dot(&mPosition, &mUp);
	float z = -D3DXVec3Dot(&mPosition, &mLook);*/

	mView(0,0) = mRight.x; 
	mView(1,0) = mRight.y; 
	mView(2,0) = mRight.z; 
	mView(3,0) = x;   

	mView(0,1) = mUp.x;
	mView(1,1) = mUp.y;
	mView(2,1) = mUp.z;
	mView(3,1) = y;  

	mView(0,2) = mLook.x; 
	mView(1,2) = mLook.y; 
	mView(2,2) = mLook.z; 
	mView(3,2) = z;   

	mView(0,3) = 0.0f;
	mView(1,3) = 0.0f;
	mView(2,3) = 0.0f;
	mView(3,3) = 1.0f;
}

void Camera::rebuildViewOld()
{
	// Keep camera's axes orthogonal to each other and of unit length.

	D3DXVec3Normalize((D3DXVECTOR3*)&mLook, (D3DXVECTOR3*)&mLook);

	D3DXVec3Cross((D3DXVECTOR3*)&mUp, (D3DXVECTOR3*)&mLook, (D3DXVECTOR3*)&mRight);
	D3DXVec3Normalize((D3DXVECTOR3*)&mUp, (D3DXVECTOR3*)&mUp);

	D3DXVec3Cross((D3DXVECTOR3*)&mRight, (D3DXVECTOR3*)&mUp, (D3DXVECTOR3*)&mLook);
	D3DXVec3Normalize((D3DXVECTOR3*)&mRight, (D3DXVECTOR3*)&mRight);


	// Fill in the view matrix entries.
	float x = -D3DXVec3Dot((D3DXVECTOR3*)&mPosition, (D3DXVECTOR3*)&mRight);
	float y = -D3DXVec3Dot((D3DXVECTOR3*)&mPosition, (D3DXVECTOR3*)&mUp);
	float z = -D3DXVec3Dot((D3DXVECTOR3*)&mPosition, (D3DXVECTOR3*)&mLook);

	mView(0,0) = mRight.x; 
	mView(1,0) = mRight.y; 
	mView(2,0) = mRight.z; 
	mView(3,0) = x;   

	mView(0,1) = mUp.x;
	mView(1,1) = mUp.y;
	mView(2,1) = mUp.z;
	mView(3,1) = y;  

	mView(0,2) = mLook.x; 
	mView(1,2) = mLook.y; 
	mView(2,2) = mLook.z; 
	mView(3,2) = z;   

	mView(0,3) = 0.0f;
	mView(1,3) = 0.0f;
	mView(2,3) = 0.0f;
	mView(3,3) = 1.0f;
}

